
#include "../inc/package.h"
#include <time.h>
#include <chrono>

#define BigEndian 1   
#define LittleEndian 0  

bool BigEndianTest()
{
	const short n = 1;  
    if(*(char *)&n)  
    {  
        return LittleEndian;  
    }  
    return BigEndian;  
}

uint64_t ntohll(uint64_t val)
{
     if (BigEndianTest() == LittleEndian)
	 {
		 return (((uint64_t)htonl((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32));
     }
     else
	 {
         return val;
	 }
}
 
uint64_t htonll(uint64_t val)
{
     if (BigEndianTest() == LittleEndian)
	 {
		 return (((uint64_t)htonl((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32));
     }
     else
	 {
         return val; 
     }
}

uint64_t gettimepoint()
{
	using namespace std::chrono;
	std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
	auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
	return tmp.count();
}

PackageHeader::PackageHeader()
{
	memset(this,0,sizeof(PackageHeader));
	flag1_ = flag2_ = PackageFlag;
	version_ = Version;
	offset_ = PackageHeaderLength;
}
PackageHeader::PackageHeader(const PackageHeader& header)
{
	memcpy(this,&header,sizeof(PackageHeader));
}
void PackageHeader::read(const char* buffer)
{
	memcpy(this,buffer,sizeof(PackageHeader));
	options_ = ntohs(options_);
	codeinfo_ = ntohs(codeinfo_);
	multipageinfo_ = ntohs(multipageinfo_);
	serialnum_ = ntohl(serialnum_);
	bodysize_ = ntohl(bodysize_);
	srcaddr_ = ntohl(srcaddr_);
	dstaddr_ = ntohl(dstaddr_);
	command_ = ntohl(command_);
	code_ = ntohs(code_);
}
void PackageHeader::write(char* buffer)const
{
	memcpy(buffer,this,sizeof(PackageHeader));
	PackageHeader* header=(PackageHeader*)buffer;
	header->options_ = htons(header->options_);
	header->codeinfo_ = htons(header->codeinfo_);
	header->multipageinfo_ = htons(header->multipageinfo_);
	header->serialnum_ = htonl(header->serialnum_);
	header->bodysize_ = htonl(header->bodysize_);
	header->srcaddr_ = htonl(header->srcaddr_);
	header->dstaddr_ = htonl(header->dstaddr_);
	header->command_ = htonl(header->command_);
	header->code_ = htons(header->code_);

	CalculateCrc(buffer);
}
void PackageHeader::CalculateCrc(char* buffer)
{
	PackageHeader* header = (PackageHeader*)buffer;
	unsigned char crc = 0;
	unsigned char *p = (unsigned char*)buffer + (size_t)&(((PackageHeader*)0)->version_);
	for (int i = 0; i < header->offset_ - 3; i++)
	{
		crc += (*p);
		p++;
	}
	header->crc_ = crc;
}
string PackageHeader::DebugString() const
{
	char buf[1024];
	memset(buf, 0, sizeof(buf));
	if (type_ == PackageHeader::Request)
		snprintf(buf, sizeof(buf)-1, "Request-serial:%d,type:%d,cmd:0x%x,bodysize:%d,src:%s,dst:%s,code:%x,options:%x,seq:%d,codeinfo:%x,priority:%x", serialnum_, type_, command_, bodysize_, AppAddress(srcaddr_).toString().c_str(), AppAddress(dstaddr_).toString().c_str(), code_, options_, issequence_, codeinfo_, ispriority_);
	else if (type_ == PackageHeader::Response)
		snprintf(buf, sizeof(buf)-1, "Response-serial:%d,type:%d,cmd:0x%x,bodysize:%d,src:%s,dst:%s,code:%x,options:%x,seq:%d,codeinfo:%x,priority:%x,pageno=%d", serialnum_, type_, command_, bodysize_, AppAddress(srcaddr_).toString().c_str(), AppAddress(dstaddr_).toString().c_str(), code_, options_, issequence_, codeinfo_, ispriority_, pageno_);
	else if (type_ == PackageHeader::Publish)
		snprintf(buf, sizeof(buf)-1, "Publish-serial:%d,type:%d,cmd:0x%x,bodysize:%d,src:%s,dst:%s,code:%x,options:%x,seq:%d,codeinfo:%x,priority:%x", serialnum_, type_, command_, bodysize_, AppAddress(srcaddr_).toString().c_str(), AppAddress(dstaddr_).toString().c_str(), code_, options_, issequence_, codeinfo_, ispriority_);
	else
		snprintf(buf, sizeof(buf)-1, "Undefined-serial:%d,type:%d,cmd:0x%x,bodysize:%d,src:%s,dst:%s,code:%x,options:%x,seq:%d,codeinfo:%x,priority:%x", serialnum_, type_, command_, bodysize_, AppAddress(srcaddr_).toString().c_str(), AppAddress(dstaddr_).toString().c_str(), code_, options_, issequence_, codeinfo_, ispriority_);
	return std::string(buf);
}
bool PackageHeader::CheckCrc(const char* buffer)
{
	PackageHeader* header = (PackageHeader*)buffer;
	unsigned char crc = 0;
	unsigned char *p = (unsigned char*)buffer + (size_t)&(((PackageHeader*)0)->version_);
	for (int i = 0; i < header->offset_ - 3; i++)
	{
		crc += (*p);
		p++;
	}
	return crc==header->crc_;
}
Package::Package()
{
	::time(&time_);
}
Package::Package(const PackageHeader& header, const std::string& classtype, const char* data, size_t packagesize, MessagePtr message)
{
	memcpy(&header_,&header,PackageHeaderLength);
	message_ = message;
	classtype_ = classtype;
	content_=nullptr;
	if (packagesize>0)
	{
		content_ = new char[packagesize];
		memcpy(content_, data, packagesize);
	}
	packagesize_ = packagesize;
	::time(&time_);
}

Package::~Package()
{
	delete[] content_;
}

void Package::SetSrcAddr(unsigned int addr)
{
	header_.srcaddr_ = addr;
	if (content_)
	{
		addr=htonl(addr);
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->srcaddr_), &addr, sizeof(addr));
		PackageHeader::CalculateCrc(content_);
	}
	
}
unsigned int Package::GetSrcAddr()
{
	return header_.srcaddr_;
}
void Package::SetDstAddr(unsigned int addr)
{
	header_.dstaddr_ = addr;
	if (content_)
	{
		addr=htonl(addr);
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->dstaddr_), &addr, sizeof(addr));
		PackageHeader::CalculateCrc(content_);
	}
}
unsigned int Package::GetDstAddr()
{
	return header_.dstaddr_;
}
void Package::SetSerialNum(unsigned int serial)
{
	header_.serialnum_ = serial;
	if (content_)
	{
		unsigned int serialnum = htonl(header_.serialnum_);
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->serialnum_), &serialnum, sizeof(serialnum));
		PackageHeader::CalculateCrc(content_);
	}
}
bool Package::AddBrokerTrace(unsigned char brokerid)
{
	bool ret = header_.add_brokertrace(brokerid);
	if (ret && content_)
	{
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->brokertrace_), &header_.brokertrace_, sizeof(header_.brokertrace_));
		PackageHeader::CalculateCrc(content_);
	}
	return ret;
}
void Package::SetCode(unsigned short code)
{
	header_.code_ = code;
	if (content_)
	{
		code = htons(code);
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->code_), &code, sizeof(code));
		PackageHeader::CalculateCrc(content_);
	}
}
void Package::SetPriority(bool priority)
{
	header_.set_ispriority(priority);
	if (content_)
	{
		unsigned short options = htons(header_.options_);
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->options_), &options, sizeof(options));
		PackageHeader::CalculateCrc(content_);
	}
}
void Package::SetPackageType(PackageHeader::MsgType packagetype)
{
	header_.set_type(packagetype);
	if (content_)
	{
		unsigned char type = header_.type_;
		memcpy(content_ + (size_t)&(((PackageHeader*)0)->type_), &type, sizeof(type));
		PackageHeader::CalculateCrc(content_);
	}
}
PackageHeader::MsgType Package::GetPackageType()
{
	return (PackageHeader::MsgType)header_.type();
}

std::string Package::DebugString(bool showHexContent)
{ 
	std::string ret = header_.DebugString();
	/*if(m_pMsg)
		ret+=m_pMsg->ShortDebugString();*/
	if (classtype_.size()>0)
	{
		ret+=",class:";
		ret += classtype_;
	}
	if(showHexContent)
	{
		std::string content="Content:";
		for (int i = 0; i<packagesize_; i++)
		{
			char buf[3];
			memset(buf, 0, sizeof(buf));
			snprintf(buf, 3, "%02X", (unsigned char)(*(content_ + i)));
			buf[2]=0;
			content.append(buf);
		}
		ret+=content;
	}
	return ret;
}

char* Package::GetBodyData()
{ 
	return content_ + header_.offset();
}
unsigned int Package::GetBodySize()
{ 
	return header_.bodysize();
}
unsigned int Package::GetSerialNum()
{ 
	return header_.serialnum();
}
int Package::GetCommand()
{ 
	return header_.command();
}
bool Package::IsMulticast() 
{ 
	return header_.ismulticast();
}
bool Package::IsRequest()
{ 
	return header_.type() == PackageHeader::MsgType::Request;
}
bool Package::IsResponse()
{ 
	return header_.type() == PackageHeader::MsgType::Response;
}
bool Package::IsPublish()
{ 
	return header_.type() == PackageHeader::MsgType::Publish;
}
